<template>
  <div ref="container" class="w-full h-full bg-transparent">
    <!-- Loading indicator -->
    <div v-if="loading" class="absolute inset-0 flex items-center justify-center text-white bg-black/20 rounded-lg">
      <div class="text-center">
        <div class="animate-spin rounded-full h-8 w-8 border-b-2 border-white mx-auto mb-2"></div>
        Loading photos...
      </div>
    </div>

    <!-- Photo detail modal -->
    <div
        v-if="modalVisible"
        class="fixed inset-0 z-50 flex items-center justify-center bg-transparent/50 backdrop-blur-sm"
        @click="closeModal"
    >
      <div class="bg-white/10 backdrop-blur-sm rounded-lg  w-[50%] max-h-[90vh] overflow-auto" @click.stop >
        <div class="flex flex-col items-center space-y-4">
          <img
              :src="selectedPhoto?.url"
              :alt="selectedPhoto?.title"
              class="w-full h-auto rounded-lg shadow-xl max-h-[60vh] object-contain"
          />
          <h3 class="text-xl font-bold mt-4">{{ selectedPhoto?.title }}</h3>
          <p class="text-gray-600">{{ selectedPhoto?.description }}</p>
        </div>
      </div>
    </div>

    <!-- Hover info card -->
    <div
        v-if="hoveredPhoto"
        class="fixed px-4 py-2 bg-black/80 text-white rounded-lg text-sm pointer-events-none z-40 border border-white/20"
        :style="hoverCardStyle"
    >
      <p class="font-medium">{{ hoveredPhoto.title }}</p>
    </div>
  </div>
</template>

<script setup>
import {ref, onMounted, onUnmounted, onBeforeUnmount, watch, nextTick} from 'vue';
import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';

const props = defineProps({
  photos: {
    type: Array,
    default: () => [],
    validator: (value) => value.length <= 100
  }
});

const container = ref(null);
const modalVisible = ref(false);
const selectedPhoto = ref(null);
const hoveredPhoto = ref(null);
const loading = ref(true);
const hoverCardStyle = ref({
  display: 'none',
  left: '0px',
  top: '0px'
});

let scene, camera, renderer, controls;
let photoGroup;
let isRotating = true;
let raycaster;
let mouse;
let photoMeshes = [];
let animationFrameId;
let resizeObserver;

// 获取容器尺寸的函数
const getContainerDimensions = () => {
  if (!container.value) return { width: 800, height: 600 };
  const rect = container.value.getBoundingClientRect();
  return {
    width: rect.width || 800,
    height: rect.height || 600
  };
};

const init = () => {
  if (!container.value) return;

  scene = new THREE.Scene();

  const { width, height } = getContainerDimensions();

  camera = new THREE.PerspectiveCamera(75, width / height, 0.1, 1000);
  camera.position.z = 5;

  renderer = new THREE.WebGLRenderer({
    antialias: true,
    alpha: true,
    powerPreference: "high-performance"
  });

  // 使用容器尺寸而不是window尺寸
  renderer.setSize(width, height);
  renderer.setClearColor(0x000000, 0);
  container.value.appendChild(renderer.domElement);

  controls = new OrbitControls(camera, renderer.domElement);
  controls.enableDamping = true;
  controls.dampingFactor = 0.05;
  controls.rotateSpeed = 0.5;

  raycaster = new THREE.Raycaster();
  mouse = new THREE.Vector2();

  // 设置ResizeObserver来监听容器尺寸变化
  if (window.ResizeObserver) {
    resizeObserver = new ResizeObserver(onContainerResize);
    resizeObserver.observe(container.value);
  }

  createPhotoSphere();
};

const textureLoader = new THREE.TextureLoader();

const loadTexture = (url) => {
  return new Promise((resolve, reject) => {
    textureLoader.load(
        url,
        (texture) => {
          texture.minFilter = THREE.LinearFilter;
          texture.generateMipmaps = false;
          resolve(texture);
        },
        undefined,
        (error) => {
          console.error('Failed to load texture:', url, error);
          reject(error);
        }
    );
  });
};

// 监听 props 的变化
watch(
    () => props.photos,
    (newPhotos, oldPhotos) => {
      if (newPhotos.length > 0) {
        loading.value = true;
        createPhotoSphere();
      }
    },
    { deep: true }
);

const createPhotoMesh = async (photo, phi, theta) => {
  try {
    const texture = await loadTexture(photo.url);
    const photoGeometry = new THREE.CircleGeometry(0.2, 16);
    const photoMaterial = new THREE.MeshBasicMaterial({
      map: texture,
      side: THREE.DoubleSide,
      transparent: true
    });

    const photoMesh = new THREE.Mesh(photoGeometry, photoMaterial);
    const radius = 2;
    photoMesh.position.setFromSpherical(new THREE.Spherical(radius, phi, theta));
    photoMesh.lookAt(0, 0, 0);
    photoMesh.userData = { photo, originalScale: photoMesh.scale.clone() };

    return photoMesh;
  } catch (error) {
    console.error('Failed to create photo mesh for:', photo.title, error);
    return null;
  }
};

const createPhotoSphere = async () => {
  if (!scene || props.photos.length === 0) return;

  // 清理现有的photoGroup
  if (photoGroup) {
    scene.remove(photoGroup);
    // 清理材质和几何体
    photoMeshes.forEach(mesh => {
      if (mesh.geometry) mesh.geometry.dispose();
      if (mesh.material) {
        if (Array.isArray(mesh.material)) {
          mesh.material.forEach(material => material.dispose());
        } else {
          mesh.material.dispose();
        }
      }
    });
  }

  photoGroup = new THREE.Group();
  photoMeshes = [];
  scene.add(photoGroup);

  console.log('Creating photo sphere with', props.photos.length, 'photos');

  const meshPromises = props.photos.map(async (photo, i) => {
    const phi = Math.acos(-1 + (2 * i) / props.photos.length);
    const theta = Math.sqrt(props.photos.length * Math.PI) * phi;
    return createPhotoMesh(photo, phi, theta);
  });

  const meshes = await Promise.all(meshPromises);
  meshes.forEach(mesh => {
    if (mesh) {
      photoGroup.add(mesh);
      photoMeshes.push(mesh);
    }
  });

  loading.value = false;
};

const animate = () => {
  animationFrameId = requestAnimationFrame(animate);

  if (isRotating && photoGroup) {
    photoGroup.rotation.y += 0.001;
  }

  updatePhotoVisibility();

  if (controls) controls.update();
  checkIntersection();
  if (renderer && scene && camera) {
    renderer.render(scene, camera);
  }
};

const updatePhotoVisibility = () => {
  if (!camera) return;

  const cameraPosition = new THREE.Vector3();
  camera.getWorldPosition(cameraPosition);

  photoMeshes.forEach(mesh => {
    const distance = mesh.position.distanceTo(cameraPosition);
    if (distance > 10) {
      mesh.visible = false;
    } else {
      mesh.visible = true;
      const scale = Math.max(0.1, 1 - (distance / 4) * 0.5);
      mesh.scale.setScalar(scale);
    }
  });
};

const checkIntersection = () => {
  if (!camera) return;

  raycaster.setFromCamera(mouse, camera);
  const intersects = raycaster.intersectObjects(photoMeshes);

  // Reset all photos to original scale
  photoMeshes.forEach(mesh => {
    if (mesh.visible && mesh.userData.originalScale) {
      mesh.scale.copy(mesh.userData.originalScale);
    }
  });

  if (intersects.length > 0) {
    const intersected = intersects[0].object;
    intersected.scale.multiplyScalar(1.2);

    if (!hoveredPhoto.value || hoveredPhoto.value !== intersected.userData.photo) {
      hoveredPhoto.value = intersected.userData.photo;
      updateHoverCard(intersected);
    }
  } else {
    hoveredPhoto.value = null;
    hoverCardStyle.value.display = 'none';
  }
};

const updateHoverCard = (intersected) => {
  if (!camera || !container.value) return;

  const vector = intersected.position.clone();
  vector.project(camera);

  const rect = container.value.getBoundingClientRect();
  const x = (vector.x * 0.5 + 0.5) * rect.width + rect.left;
  const y = -(vector.y * 0.5 - 0.5) * rect.height + rect.top;

  hoverCardStyle.value = {
    display: 'block',
    left: `${x + 10}px`,
    top: `${y - 10}px`,
    transform: 'translate(-50%, -50%)'
  };
};

const onMouseMove = (event) => {
  if (!container.value) return;

  const rect = container.value.getBoundingClientRect();
  // 使用容器相对坐标而不是window坐标
  mouse.x = ((event.clientX - rect.left) / rect.width) * 2 - 1;
  mouse.y = -((event.clientY - rect.top) / rect.height) * 2 + 1;

  // Check if mouse is over the sphere
  if (camera) {
    raycaster.setFromCamera(mouse, camera);
    const intersects = raycaster.intersectObjects(photoMeshes);
    isRotating = intersects.length === 0;
  }
};

const onClick = (event) => {
  if (!camera || !container.value) return;

  const rect = container.value.getBoundingClientRect();
  mouse.x = ((event.clientX - rect.left) / rect.width) * 2 - 1;
  mouse.y = -((event.clientY - rect.top) / rect.height) * 2 + 1;

  raycaster.setFromCamera(mouse, camera);
  const intersects = raycaster.intersectObjects(photoMeshes);

  if (intersects.length > 0) {
    const clicked = intersects[0].object;
    selectedPhoto.value = clicked.userData.photo;
    modalVisible.value = true;
  }
};

const closeModal = () => {
  modalVisible.value = false;
  selectedPhoto.value = null;
};

// 容器尺寸变化处理函数
const onContainerResize = () => {
  if (!camera || !renderer || !container.value) return;

  const { width, height } = getContainerDimensions();
  camera.aspect = width / height;
  camera.updateProjectionMatrix();
  renderer.setSize(width, height);
};

// 窗口尺寸变化处理函数（作为备用）
const onWindowResize = () => {
  onContainerResize();
};

const cleanup = () => {
  // 取消动画帧
  if (animationFrameId) {
    cancelAnimationFrame(animationFrameId);
  }

  // 移除事件监听器
  if (renderer && renderer.domElement) {
    renderer.domElement.removeEventListener('mousemove', onMouseMove);
    renderer.domElement.removeEventListener('click', onClick);
  }

  window.removeEventListener('resize', onWindowResize);

  // 停止ResizeObserver
  if (resizeObserver) {
    resizeObserver.disconnect();
  }

  // 清理Three.js资源
  if (scene) {
    scene.traverse(object => {
      if (object.geometry) {
        object.geometry.dispose();
      }
      if (object.material) {
        if (Array.isArray(object.material)) {
          object.material.forEach(material => material.dispose());
        } else {
          object.material.dispose();
        }
      }
    });
  }

  if (renderer) {
    renderer.dispose();
  }

  if (controls) {
    controls.dispose();
  }
};

onMounted(async () => {
  await nextTick(); // 确保DOM已渲染
  init();
  animate();

  // 添加事件监听器
  window.addEventListener('resize', onWindowResize);
  if (renderer && renderer.domElement) {
    renderer.domElement.addEventListener('mousemove', onMouseMove);
    renderer.domElement.addEventListener('click', onClick);
  }
});

onUnmounted(() => {
  cleanup();
});

onBeforeUnmount(() => {
  cleanup();
});
</script>

<style scoped>
/* 确保容器有明确的尺寸 */
.w-full.h-full {
  min-height: 400px;
}

/* 优化模态框样式 */
.fixed.inset-0 {
  backdrop-filter: blur(8px);
}

/* 优化加载动画 */
@keyframes spin {
  to {
    transform: rotate(360deg);
  }
}

.animate-spin {
  animation: spin 1s linear infinite;
}
</style>